#include "StdAfx.h"

#include "Helper.h"

#include "ControllerOpt.h"

#include "CharacterInstance.h"
#include "SkeletonAnim.h"
#include "SkeletonPose.h"

#include "Command_Buffer.h"
#include "Command_Commands.h"

#include "Skeleton.h"
#include "LoaderDBA.h"

uint32 g_SkeletonUpdates=0;

extern float g_YLine;

namespace Command {

void LoadControllers(GlobalAnimationHeaderCAF& rGAH, const Command::CState& state, IController* controllers[MAX_JOINT_AMOUNT])
{
	uint32 num=sizeof(controllers);
	memset(controllers, 0, sizeof(controllers)*MAX_JOINT_AMOUNT);


	if (rGAH.IsAssetOnDemand())
	{
		assert(rGAH.IsAssetLoaded());
		if (rGAH.IsAssetLoaded()==0)
		{
			return;
			//	int nCurrentFrameID = g_pCharacterManager->m_nUpdateCounter; 
			//	CryFatalError("CryAnimation: Asset Not Loaded: %s   nCurrentFrameID: %d  Weight: %f",rCAF.GetFilePath(),nCurrentFrameID,ac.m_fWeight);
		}
	}

	if (rGAH.m_nControllers2)
	{
		if (rGAH.m_nControllers==0)
		{
			uint32 dba_exists=0;
			if (rGAH.m_FilePathDBACRC32)
			{
				size_t numDBA_Files = g_AnimationManager.m_arrGlobalHeaderDBA.size();
				for (uint32 d=0; d<numDBA_Files; d++)
				{
					CGlobalHeaderDBA& pGlobalHeaderDBA = g_AnimationManager.m_arrGlobalHeaderDBA[d];
					if (rGAH.m_FilePathDBACRC32!=pGlobalHeaderDBA.m_FilePathDBACRC32)
						continue;

					dba_exists++;
					break;
				}

			}

#if !defined(__SPU__)
			if (dba_exists)
			{
				if (Console::GetInst().ca_DebugCriticalErrors)
				{
					//this case is virtually impossible, unless something went wrong with a DBA or maybe a CAF in a DBA was compressed to death and all controllers removed
					//	const char* mname = state.m_pInstance->GetFilePath();
					//	f32 fColor[4] = {1,1,0,1};
					//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 1.2f, fColor, false,"model: %s",mname); 
					//	g_YLine+=0x10;
					//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.3f, fColor, false,"No Controllers found in Asset: %02x %08x %s",rGAH.m_nControllers2,rGAH.m_FilePathDBACRC32,rGAH.m_FilePath.c_str() );	
					//	g_YLine+=23.0f;
					CryFatalError("CryAnimation: No Controllers found in Asset: %s",rGAH.m_FilePath.c_str());
				}

				g_pISystem->Warning( VALIDATOR_MODULE_ANIMATION,VALIDATOR_WARNING, VALIDATOR_FLAG_FILE, 0 , "No Controllers found in Asset: %s" ,rGAH.m_FilePath.c_str() );
			}
#endif

			return;  //return and don't play animation, because we don't have any controllers
		}
	}

	uint32* pLodJointMask = NULL;
	uint32 lodJointMaskCount = 0;
	if (state.m_lod > 0)
	{
		if (uint32 lodCount = state.m_pModel->m_arrAnimationLOD.size())
		{
			uint32 lod = state.m_lod;
			if (lod > lodCount)
				lod = lodCount;
			--lod;

			pLodJointMask = &state.m_pModel->m_arrAnimationLOD[lod][0];
			lodJointMaskCount = state.m_pModel->m_arrAnimationLOD[lod].size();
		}
	}

	const CModelJoint* pModelJoint = &state.m_pModel->m_ModelSkeleton.m_arrModelJoints[0];
	uint32 jointCount = state.m_jointCount;
	for (uint32 i=0; i<jointCount; ++i)
	{
		uint32 crc32 = pModelJoint[i].m_nJointCRC32;
		if (pLodJointMask)
		{
			if (Helper::FindFromSorted<uint32>(pLodJointMask, lodJointMaskCount, crc32) == NULL)
				continue;
		}

		if (!state.IsJointActive(crc32))
			continue;

		controllers[i] = rGAH.GetControllerByJointCRC32( pModelJoint[i].m_nJointCRC32 );
	}
}



SPU_NO_INLINE void ClearFull::Execute(const CState& state, void* buffers[]) const
{
	const ClearFull& ac = *this;
	void** CBTemp = buffers;

	assert( ac.m_TargetBuffer<=Command::TargetBuffer );
	QuatT*		parrRelPoseDst	= SPU_LOCAL_PTR( (QuatT*)  CBTemp[ac.m_TargetBuffer+0] );
	Status4*	parrStatusDst		= SPU_LOCAL_PTR( (Status4*)CBTemp[ac.m_TargetBuffer+1] );
	uint32 numJoints = state.m_jointCount;
	for (uint32 j=0; j<numJoints; j++)
	{
		parrRelPoseDst[j].q.v.x = 0.0f;
		parrRelPoseDst[j].q.v.y = 0.0f;
		parrRelPoseDst[j].q.v.z = 0.0f;
		parrRelPoseDst[j].q.w   = 0.0f;
		parrRelPoseDst[j].t.x		= 0.0f;
		parrRelPoseDst[j].t.y		= 0.0f;
		parrRelPoseDst[j].t.z		= 0.0f;
		parrStatusDst[j].o = 1;
		parrStatusDst[j].p = 1;
		parrStatusDst[j].s = 0;
	} 
}

SPU_NO_INLINE void ClearSingle::Execute(const CState& state, void* buffers[]) const
{
	const ClearSingle& ac = *this;
	void** CBTemp = buffers;

	assert( ac.m_TargetBuffer<=Command::TargetBuffer );
	QuatT*		parrRelPoseDst	= SPU_LOCAL_PTR( (QuatT*)  CBTemp[ac.m_TargetBuffer+0] );
	Status4*	parrStatusDst		= SPU_LOCAL_PTR( (Status4*)CBTemp[ac.m_TargetBuffer+1] );
	parrRelPoseDst[0].q.v.x = 0.0f;
	parrRelPoseDst[0].q.v.y = 0.0f;
	parrRelPoseDst[0].q.v.z = 0.0f;
	parrRelPoseDst[0].q.w   = 0.0f;
	parrRelPoseDst[0].t.x		= 0.0f;
	parrRelPoseDst[0].t.y		= 0.0f;
	parrRelPoseDst[0].t.z		= 0.0f;
}

SPU_NO_INLINE void SampleAddAnimFull::Execute(const CState& state, void* buffers[]) const
{
	float fColor[4] = {1,0,0,1};
	const SampleAddAnimFull& ac = *this;
	void** CBTemp = buffers;

	assert( ac.m_nEAnimID>=0   );
	int32 nBufferID=(ac.m_flags&Flag_TmpBuffer)?0:3;
	QuatT*		parrRelPoseDst	= SPU_LOCAL_PTR( (QuatT*)  CBTemp[nBufferID+0] );
	Status4*	parrStatusDst		= SPU_LOCAL_PTR( (Status4*)CBTemp[nBufferID+1] );

	uint32 numJoints = state.m_jointCount;
	Status4 &getOPResult = parrStatusDst[0];








	CAnimationSet* pAnimationSet = &state.m_pModel->m_AnimationSet;
	const ModelAnimationHeader* pMAG = pAnimationSet->GetModelAnimationHeader(ac.m_nEAnimID);
	assert(pMAG);
	int32 nEGlobalID = pMAG->m_nGlobalAnimId;
	assert(pMAG->m_nAssetType==CAF_File);

#if !defined(__SPU__)
	assert(nEGlobalID>=0);
	if (nEGlobalID<0)
	{
		AnimFileWarning(state.m_pModel->GetModelFilePath(),"illegal index in RSingleEvaluation:  index: %d",nEGlobalID);
	}
#endif // !__SPU__

	// use a stack object on SPU here to reduce simulation time
	SpuStackValue<GlobalAnimationHeaderCAF, true, true> stackAnimHeader( g_AnimationManager.m_arrGlobalCAF[nEGlobalID] );
	GlobalAnimationHeaderCAF& rCAF = stackAnimHeader; 

#if !defined(__SPU__)
	if (rCAF.IsAssetOnDemand())
	{
		assert(rCAF.IsAssetLoaded());
		if (rCAF.IsAssetLoaded()==0)
		{
			int nCurrentFrameID = g_pCharacterManager->m_nUpdateCounter; 
			//	CryFatalError("CryAnimation: Asset Not Loaded: %s   nCurrentFrameID: %d  Weight: %f",rCAF.GetFilePath(),nCurrentFrameID,ac.m_fWeight);
			g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.3f, fColor, false,"CryAnimation: Asset Not Loaded: %s   nCurrentFrameID: %d  Weight: %f",rCAF.GetFilePath(),nCurrentFrameID,ac.m_fWeight );	
		}
	}
#endif // !__SPU__

	InitSpuControllerLookupTable( rCAF.m_arrControllerLookupVector );

	memset( parrStatusDst,0xff,numJoints );

	IController* parrController[MAX_JOINT_AMOUNT];
	LoadControllers(rCAF, state, parrController);

	QuatT qtemp[MAX_JOINT_AMOUNT];
	QuatT* parrDefJoints = &state.m_pModel->m_ModelSkeleton.m_poseData.m_pJointsRelative[0];
	{
		DEFINE_PROFILER_SECTION("cryMemcpy");
		cryMemcpy( &qtemp[0], parrDefJoints,numJoints*sizeof(QuatT) );
	}

	f32 fDuration		= max(SECONDS_PER_TICK,rCAF.m_fTotalDuration);
	f32 fKeyTime1		= rCAF.NTime2KTime(1);
	f32 fKeyTimeNew = rCAF.NTime2KTime(ac.m_fETimeNew);

	uint32 nStartJoint=0;
	if ( ac.m_flags & Flag_ADMotion )
	{
		nStartJoint=1;
		parrRelPoseDst[0].SetIdentity();  //root is always "identity" with animation-driven motions
	}


	//-------------------------------------------------------------------------------------
	//----             evaluate all controllers for this animation                    -----
	//-------------------------------------------------------------------------------------
	uint32 nAdditiveAnimation = rCAF.IsAssetAdditive();
	if (nAdditiveAnimation)
	{
		//additive asset
		for (uint32 j=nStartJoint; j<numJoints; j++)
		{
			if (parrController[j])
			{
				Status4 ops=SPU_MAIN_PTR(parrController[j])->GetOP( fKeyTimeNew, qtemp[j].q, qtemp[j].t );
				if (ops.o)
					qtemp[j].q=qtemp[j].q*parrDefJoints[j].q;	
				if (ops.p)
					qtemp[j].t=qtemp[j].t+parrDefJoints[j].t;	
				qtemp[j].q *= fsgnnz(parrDefJoints[j].q|qtemp[j].q);  //this could be optimized at loading-time
			}
			assert( qtemp[j].q.IsUnit() );
			assert( qtemp[j].q.IsValid() );
			assert( qtemp[j].t.IsValid() );
			parrRelPoseDst[j].q   += ac.m_fWeight*qtemp[j].q;
			parrRelPoseDst[j].t   += ac.m_fWeight*qtemp[j].t;
		} 
	}
	else
	{
		//overwrite asset
		for (uint32 j=nStartJoint; j<numJoints; j++)
		{
			if (parrController[j])
			{
				SPU_MAIN_PTR(parrController[j])->GetOP( fKeyTimeNew, qtemp[j].q, qtemp[j].t );	
				qtemp[j].q *= fsgnnz(parrDefJoints[j].q|qtemp[j].q);  //this could be optimized at loading-time
			}
			assert( qtemp[j].q.IsUnit() );
			assert( qtemp[j].q.IsValid() );
			assert( qtemp[j].t.IsValid() );
			parrRelPoseDst[j].q   += ac.m_fWeight*qtemp[j].q;
			parrRelPoseDst[j].t   += ac.m_fWeight*qtemp[j].t;
		} 
	}

#ifdef _DEBUG
	for (uint32 j=0; j<numJoints; j++)
	{
		Quat q = parrRelPoseDst[j].q;
		assert( q.IsValid() );
		Vec3 t = parrRelPoseDst[j].t;
		assert( t.IsValid() );
	}
#endif			

#if !defined(__SPU__)
	g_SkeletonUpdates++;
#endif // __SPU__
}

SPU_NO_INLINE void SampleAddPoseFull::Execute(const CState& state, void* buffers[]) const
{
	const SampleAddPoseFull& ac = *this;
	void** CBTemp = buffers;

	assert( ac.m_nEAnimID>=0   );
	int32 nBufferID=(ac.m_flags&SampleAddAnimFull::Flag_TmpBuffer)?0:3;
	QuatT*		parrRelPoseDst	= SPU_LOCAL_PTR( (QuatT*)  CBTemp[nBufferID+0] );
	Status4*	parrStatusDst		= SPU_LOCAL_PTR( (Status4*)CBTemp[nBufferID+1] );

	uint32 numJoints = state.m_jointCount;
	Status4 &getOPResult = parrStatusDst[0];

	CAnimationSet* pAnimationSet = &state.m_pModel->m_AnimationSet;
	const ModelAnimationHeader* pMAG = pAnimationSet->GetModelAnimationHeader(ac.m_nEAnimID);
	assert(pMAG);
	int32 nEGlobalID = pMAG->m_nGlobalAnimId;
	assert(pMAG->m_nAssetType==AIM_File);

	// use a stack object on SPU here to reduce simulation time
	SpuStackValue<GlobalAnimationHeaderAIM, true, true> stackAnimHeader( g_AnimationManager.m_arrGlobalAIM[nEGlobalID] );
	GlobalAnimationHeaderAIM& rGlobalAnimHeaderAIM = stackAnimHeader; 

	memset( parrStatusDst,0xff,numJoints );
	const CModelJoint* pModelJoint = &state.m_pModel->m_ModelSkeleton.m_arrModelJoints[0];
	IController* parrController[MAX_JOINT_AMOUNT];
	memset(parrController, 0, sizeof(parrController));
	for (uint32 i=0; i<numJoints; ++i)
		parrController[i] = rGlobalAnimHeaderAIM.GetControllerByJointCRC32( pModelJoint[i].m_nJointCRC32 );

	QuatT qtemp[MAX_JOINT_AMOUNT];
	QuatT* parrDefJoints = &state.m_pModel->m_ModelSkeleton.m_poseData.m_pJointsRelative[0];
	cryMemcpy( &qtemp[0], parrDefJoints,numJoints*sizeof(QuatT) );

	f32 fKeyTimeNew =rGlobalAnimHeaderAIM.NTime2KTime(ac.m_fETimeNew);

	//-------------------------------------------------------------------------------------
	//----             evaluate all controllers for this animation                    -----
	//-------------------------------------------------------------------------------------
	for (uint32 j=0; j<numJoints; j++)
	{
		if (parrController[j])
		{
			SPU_MAIN_PTR(parrController[j])->GetOP( fKeyTimeNew, qtemp[j].q, qtemp[j].t );	
			//this could be optimized at loading-time
			f32 dot=parrDefJoints[j].q|qtemp[j].q;
			if (dot<0)
				qtemp[j].q=-qtemp[j].q;
		}
		assert( qtemp[j].q.IsUnit() );
		assert( qtemp[j].q.IsValid() );
		assert( qtemp[j].t.IsValid() );
		parrRelPoseDst[j].q   += ac.m_fWeight*qtemp[j].q;
		parrRelPoseDst[j].t   += ac.m_fWeight*qtemp[j].t;
	} 

#ifdef _DEBUG
	for (uint32 j=0; j<numJoints; j++)
	{
		Quat q = parrRelPoseDst[j].q;
		assert( q.IsValid() );
		Vec3 t = parrRelPoseDst[j].t;
		assert( t.IsValid() );
	}
#endif			

}

SPU_NO_INLINE void CopyAddAnimFull::Execute(const CState& state, void* buffers[]) const
{
	const CopyAddAnimFull& ac = *this;
	void** CBTemp = buffers;

	assert(ac.m_SourceBuffer<=Command::TargetBuffer);
	QuatT*		parrRelPoseSrc		= SPU_LOCAL_PTR( (QuatT*)  CBTemp[ac.m_SourceBuffer+0]);
	assert(ac.m_TargetBuffer<=Command::TargetBuffer);
	QuatT*		parrRelPoseDst		= SPU_LOCAL_PTR( (QuatT*)  CBTemp[ac.m_TargetBuffer+0]);

	f32 t=ac.m_fWeight;

	uint32 numJoints = state.m_jointCount;
	for (uint32 i=0; i<numJoints; i++)
	{
		parrRelPoseDst[i].q += parrRelPoseSrc[i].q*t;
		parrRelPoseDst[i].t += parrRelPoseSrc[i].t*t;
	}
#ifdef _DEBUG
	for (uint32 j=0; j<numJoints; j++)
	{
		assert( parrRelPoseDst[j].q.IsValid() );
		assert( parrRelPoseDst[j].t.IsValid() );
	}
#endif			
}

SPU_NO_INLINE void NormalizeFull::Execute(const CState& state, void* buffers[]) const
{
	const NormalizeFull& ac = *this;
	void** CBTemp = buffers;

	assert(ac.m_TargetBuffer<=Command::TargetBuffer);
	QuatT*			parrRelPoseDst	= SPU_LOCAL_PTR((QuatT*)  CBTemp[ac.m_TargetBuffer+0]);
	Status4*		parrStatusDst		= SPU_LOCAL_PTR((Status4*)CBTemp[ac.m_TargetBuffer+1]);

	f32 dot = fabsf(parrRelPoseDst[0].q|parrRelPoseDst[0].q);
	if (dot>0.0001f)
		parrRelPoseDst[0].q.Normalize();
	else 
		parrRelPoseDst[0].q.SetIdentity();

	uint32 numJoints = state.m_jointCount;
	for (uint32 i=1; i<numJoints; i++)
	{
		parrRelPoseDst[i].q.Normalize();
		assert( parrRelPoseDst[i].q.IsUnit() );
	}
}

SPU_NO_INLINE void ScaleUniformFull::Execute(const CState& state, void* buffers[]) const
{
	const ScaleUniformFull& ac = *this;
	void** CBTemp = buffers;

	assert(ac.m_TargetBuffer<=Command::TargetBuffer);
	QuatT*			parrRelPoseDst	= SPU_LOCAL_PTR((QuatT*)    CBTemp[ac.m_TargetBuffer+0]);
	Status4*		parrStatusDst		= SPU_LOCAL_PTR((Status4*)  CBTemp[ac.m_TargetBuffer+1]);
	uint32 numJoints = state.m_jointCount;
	for (uint32 j=0; j<numJoints; j++)
	{
		if (parrStatusDst[j].o)
			parrRelPoseDst[j].t *= ac.m_fScale;
	}
#ifdef _DEBUG
	for (uint32 j=0; j<numJoints; j++)
	{
		assert( parrRelPoseDst[j].q.IsValid() );
		assert( parrRelPoseDst[j].t.IsValid() );
	}
#endif			

}

SPU_NO_INLINE void SampleAnimPart::Execute(const CState& state, void* buffers[]) const
{
	const SampleAnimPart& ac = *this;
	void** CBTemp = buffers;

	assert(ac.m_nEAnimID>=0);
	assert(ac.m_TargetBuffer<=Command::TargetBuffer);
	QuatT*			parrRelPoseDst	= SPU_LOCAL_PTR( (QuatT*)    CBTemp[ac.m_TargetBuffer+0] );
	Status4*		parrStatusDst		= SPU_LOCAL_PTR( (Status4*)  CBTemp[ac.m_TargetBuffer+1] );

	SampleFeatherAnimPart* pFeatherMask=0;
	if (ac.m_nFeatherBlend)
		pFeatherMask=(SampleFeatherAnimPart*)&ac;

	CAnimationSet* pAnimationSet = &state.m_pModel->m_AnimationSet;
	const ModelAnimationHeader* pMAG = pAnimationSet->GetModelAnimationHeader(ac.m_nEAnimID);
	assert(pMAG);
	int32 nEGlobalID = pMAG->m_nGlobalAnimId;
	assert(pMAG->m_nAssetType==CAF_File);

	// cache vars to local pointers (spares using this pointer everytime)
	uint32 numJoints = state.m_jointCount;
	assert(ac.m_fAnimTime>=0.0f && ac.m_fAnimTime<=1.0f);	


	GlobalAnimationHeaderCAF& rCAF = SPU_MAIN_REF( g_AnimationManager.m_arrGlobalCAF[nEGlobalID] );
	InitSpuControllerLookupTable( rCAF.m_arrControllerLookupVector );
	uint32 nAdditiveAnimation = rCAF.IsAssetAdditive();

	IController* parrController[MAX_JOINT_AMOUNT];
	LoadControllers(rCAF, state, parrController);

	f32 fKeyTimeNew = rCAF.NTime2KTime(ac.m_fAnimTime);
	const CModelJoint* pModelJoint = &state.m_pModel->m_ModelSkeleton.m_arrModelJoints[0];

	//-------------------------------------------------------------------------------------
	//----             evaluate all controllers for this animation                    -----
	//-------------------------------------------------------------------------------------
#if !defined(__SPU__)
	g_SkeletonUpdates++;
#endif // !__SPU__

	if (nAdditiveAnimation)
	{
		//additive animations
		for (uint32 j=1; j<numJoints; j++)
		{
			if (pFeatherMask && pFeatherMask->m_arrFeatherMask[j]==0)
				continue;

			if (parrController[j])
			{
				Quat rot;	  Vec3 pos;
				Status4 s = SPU_MAIN_PTR(parrController[j])->GetOP(fKeyTimeNew,rot,pos);
				Status4 status;	status.ops = s.ops & parrStatusDst[j].ops;
				if (status.o)
					parrRelPoseDst[j].q = Quat::CreateNlerp(IDENTITY,rot,ac.m_fWeight)*parrRelPoseDst[j].q;
				if (status.p)
					parrRelPoseDst[j].t = Vec3::CreateLerp(ZERO,     pos,ac.m_fWeight)+parrRelPoseDst[j].t;

			}
		}
	} 
	else 
	{
		//override animations
		for (uint32 j=1; j<numJoints; j++)
		{
			if (pFeatherMask && pFeatherMask->m_arrFeatherMask[j]==0)
				continue;

			if (parrController[j])
			{
				QuatT & 	RESTRICT_REFERENCE rRelPoseDst	= parrRelPoseDst[j];
				Status4 & RESTRICT_REFERENCE rStatusDst	 	= parrStatusDst[j];
				Quat rot;	  Vec3 pos;
				Status4 status = SPU_MAIN_PTR(parrController[j])->GetOP(fKeyTimeNew,rot,pos);
				//Overwrite Mode
				if (status.o)
				{
					if (rStatusDst.o)
						rRelPoseDst.q.SetNlerp(rRelPoseDst.q,rot,ac.m_fWeight);
					else 
						rRelPoseDst.q=rot;
				}
				if (status.p)
				{
					if (rStatusDst.p)
						rRelPoseDst.t.SetLerp( rRelPoseDst.t,pos,ac.m_fWeight);
					else
						rRelPoseDst.t=pos;
				}
				rStatusDst.ops |= status.ops;
			}
		}
	}


#ifdef _DEBUG
	uint32 o=0;
	uint32 p=0;
	for (uint32 j=0; j<numJoints; j++)
	{
		assert(parrStatusDst[j].o<2);
		if (parrStatusDst[j].o)
		{
			Quat q = parrRelPoseDst[j].q;
			assert(parrRelPoseDst[j].q.IsValid());
			o++;
		}
		assert(parrStatusDst[j].p<2);
		if (parrStatusDst[j].p)
		{
			Vec3 t = parrRelPoseDst[j].t;
			assert(parrRelPoseDst[j].t.IsValid());
			p++;
		}
	}
#endif

}

SPU_NO_INLINE void SamplePosePart::Execute(const CState& state, void* buffers[]) const
{
	const SamplePosePart& ac = *this;
	void** CBTemp = buffers;

	assert(ac.m_nEAnimID>=0);
	assert(ac.m_TargetBuffer<=Command::TargetBuffer);
	QuatT* parrRelPoseDst = SPU_LOCAL_PTR((QuatT*)CBTemp[ac.m_TargetBuffer+0]);
	Status4* parrStatusDst = SPU_LOCAL_PTR((Status4*)CBTemp[ac.m_TargetBuffer+1]);

	CAnimationSet* pAnimationSet = &state.m_pModel->m_AnimationSet;
	const ModelAnimationHeader* pMAG = pAnimationSet->GetModelAnimationHeader(ac.m_nEAnimID);
	assert(pMAG);
	int32 nEGlobalID = pMAG->m_nGlobalAnimId;
	assert(pMAG->m_nAssetType==AIM_File);

	// cache vars to local pointers (spares using this pointer everytime)
	uint32 numJoints 				= state.m_jointCount;
	assert(ac.m_fAnimTime>=0.0f && ac.m_fAnimTime<=1.0f);	


	GlobalAnimationHeaderAIM& rGlobalAnimHeader = SPU_MAIN_REF( g_AnimationManager.m_arrGlobalAIM[nEGlobalID] );

	const CModelJoint* pModelJoint = &state.m_pModel->m_ModelSkeleton.m_arrModelJoints[0];

	//f32 fFadeColor[4] = {1,0,0,1};
	//if (nAdditiveAnimation)
	//	g_pIRenderer->Draw2dLabel( 1,300, 6.0f, fFadeColor, false,"SingleEvaluation" ); g_YLine+=0x18;

	//	f32 fFadeColor[4] = {1,0,0,1};
	//	g_pIRenderer->Draw2dLabel( 1,g_YLine, 2.0f, fFadeColor, false,"fTransitionBlendIn: %f   fMultiLayerBlend: %f",fTransitionBlendIn,fMultiLayerBlend); g_YLine+=0x18;

	//-------------------------------------------------------------------------------------
	//----             evaluate all controllers for this animation                    -----
	//-------------------------------------------------------------------------------------
#if !defined(__SPU__)
	g_SkeletonUpdates++;
#endif // !__SPU__

	f32 fKeyTimeNew =rGlobalAnimHeader.NTime2KTime(ac.m_fAnimTime);
	//override animations
	for (uint32 j=1; j<numJoints; j++)
	{

		IController* pController = rGlobalAnimHeader.GetControllerByJointCRC32( pModelJoint[j].m_nJointCRC32 );

		if (pController)
		{
			QuatT & 	RESTRICT_REFERENCE rRelPoseDst	= parrRelPoseDst[j];
			Status4 & RESTRICT_REFERENCE rStatusDst	 	= parrStatusDst[j];
			Quat rot;	  Vec3 pos;
			Status4 status = pController->GetOP( fKeyTimeNew, rot, pos  );
			//Overwrite Mode
			if (status.o)
			{
				if (rStatusDst.o)
					rRelPoseDst.q.SetNlerp(rRelPoseDst.q,rot,ac.m_fWeight);
				else 
					rRelPoseDst.q=rot;
			}
			if (status.p)
			{
				if (rStatusDst.p)
					rRelPoseDst.t.SetLerp( rRelPoseDst.t,pos,ac.m_fWeight);
				else
					rRelPoseDst.t=pos;
			}
			rStatusDst.ops |= status.ops;
		}
	}


#ifdef _DEBUG
	uint32 o=0;
	uint32 p=0;
	for (uint32 j=0; j<numJoints; j++)
	{
		assert(parrStatusDst[j].o<2);
		if (parrStatusDst[j].o)
		{
			Quat q = parrRelPoseDst[j].q;
			assert(parrRelPoseDst[j].q.IsValid());
			o++;
		}
		assert(parrStatusDst[j].p<2);
		if (parrStatusDst[j].p)
		{
			Vec3 t = parrRelPoseDst[j].t;
			assert(parrRelPoseDst[j].t.IsValid());
			p++;
		}
	}
#endif
}

SPU_NO_INLINE void PoseModifier::Execute(const CState& state, void* buffers[]) const
{
	const PoseModifier& ac = *this;
	void** CBTemp = buffers;

	SAnimationPoseModiferParams params;
	params.pCharacterInstance = state.m_pInstance;
	params.timeDelta = state.m_pInstance->m_fOriginalDeltaTime;
	params.locationNextPhysics = state.m_locationPhysics;
	params.locationNextAnimation = state.m_locationAnimation;
	params.pPoseRelative = (QuatT*)CBTemp[ac.m_TargetBuffer+0];
	params.pPoseAbsolute = SPU_PTR_SELECT(&state.m_pPoseData->m_pJointsAbsolute[0], gSkeletonAbsolutePose);
	params.jointCount = state.m_jointCount;
	ac.m_pPoseModifier->Execute(params);

#ifdef _DEBUG
	for (uint32 j=0; j<params.jointCount; j++)
	{
		assert( params.pPoseRelative[j].q.IsUnit() );
		assert( params.pPoseAbsolute[j].q.IsUnit() );
		assert( params.pPoseRelative[j].IsValid() );
		assert( params.pPoseAbsolute[j].IsValid() );
	}
#endif			

}

#ifdef _DEBUG
SPU_NO_INLINE void VerifyFull::Execute(const CState& state, void* buffers[]) const
{
	const VerifyFull& ac = *this;
	void** CBTemp = buffers;

	assert(ac.m_TargetBuffer<=Command::TargetBuffer);
	QuatT*			parrRelPoseDst	= SPU_LOCAL_PTR( (QuatT*)    CBTemp[ac.m_TargetBuffer+0]);
	Status4*		parrStatusDst		= SPU_LOCAL_PTR( (Status4*)  CBTemp[ac.m_TargetBuffer+1]);
	uint32 numJoints = state.m_jointCount;
	for (uint32 j=0; j<numJoints; j++)
	{
		Status4 s4 = parrStatusDst[j];
		assert(parrRelPoseDst[j].q.IsValid());
		assert(parrRelPoseDst[j].t.IsValid());
	}
}
#endif

} // namespace Command
